﻿using OWL.Rendering.HRP;
using ParadoxNotion.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using Tayx.Graphy.Utils.NumString;
using UnityEngine;
using UnityEngine.Rendering;
using UnityGameFramework.Runtime;
using Yoozoo.Framework.Managers;
using Yoozoo.Gameplay;
using Yoozoo.Gameplay.Liberty;
using Yoozoo.Gameplay.Managers;
using Yoozoo.HRP.Runtime;
using Yoozoo.Managers.ResourceManagement;
using Yoozoo.Managers.ResourceManagerV2.Framework;
using Yoozoo.Managers.ResourceManagerV2.Framework.FileSystem;
using Yoozoo.Managers.ResourceManagerV2.Framework.Resource;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using Yoozoo.Mars.Got;
using ZString;
using Color = UnityEngine.Color;

namespace Yoozoo.Gta.Common
{
    public static class GameHelper
    {
        private static string appVersion;

        public static string GetAppVersion()
        {
            if (appVersion != null)
                return appVersion;

            // GC.Alloc 24B, 固定不变的值，缓存
            appVersion = Application.version;
            return appVersion;
        }

        public static GameObject GetObjectByName(string name)
        {
            if (name.Length > 0)
            {
                try
                {
                    return GameObject.Find(name);
                }
                catch (System.Exception gen_e)
                {
                    return null;
                }
            }
            return null;
        }
        

        public static string GetFullAppVersion()
        {
            if (UMTResource.isEditorMode)
                return "Editor";
            return $"{Application.version}({AppConfig.BundleVersionCode})";
        }

        public static string GetResVersion()
        {
            string resVersion = string.Empty;
            if (UMTResource.isEditorMode == false)
            {
                resVersion = UMTResource.Resource.ResourceManager.InternalResourceVersion;
            }
            
            if (string.IsNullOrEmpty(resVersion))
            {
                resVersion = "100000";
            }

            return resVersion;
        }

        public static void QuitApplication()
        {
            ResourceV2Entry.QuitApplication();
        }

        public static void ShowDebuggerWindow()
        {
            var debuggerObj = GameObject.Find("Debugger");
            if (debuggerObj==null)
            {
                debuggerObj = new GameObject("Debugger");
            }
            var debugger =  debuggerObj.transform.GetOrAddCompoment<DebuggerComponent>();
            debugger.ShowFullWindow = true;
            debugger.enabled = true;

        }
        // 根据距离计算出物体在3D空间中的缩放值
        public static float GetCameraScale(float dis)
        {
            return 2.0f * dis * Mathf.Tan(Camera.main.fieldOfView * 0.5f * Mathf.Deg2Rad);
        }

        public static bool IsEmulator()
        {
            AndroidJavaClass osBuild;
            osBuild = new AndroidJavaClass("android.os.Build");
            string fingerPrint = osBuild.GetStatic<string>("FINGERPRINT");
            return fingerPrint.Contains("generic");
        }

        public static bool[] ReadTexture(GameObject obj,string name)
        {
            Material m = obj.GetComponent<Renderer>().material;
            Texture2D t = m.GetTexture(name) as Texture2D;
            List<bool> bu = new List<bool>();
            for (int y = 0; y < 1200; y++)
            {
                for (int x = 0; x < 1200; x++)
                {
                    Color c = t.GetPixel(x, y);
                    if (c.r > 0)
                    {
                        bu.Add(true);
                    }
                    else
                    {
                        bu.Add(false);
                    }
                }
            }
            bool[] buffer = bu.ToArray();
            return buffer;
        }


        public static bool IsDevelopmentBuild()
        {
            return  UnityEngine.Debug.isDebugBuild;
        }
        // TODO: 这里需要重新梳理下显示gm的逻辑
        public static bool IsShowGMButton()
        {
            return IsDevelopmentBuild() || !AppConfig.IsSDK || AppConfig.IsShowGM;
        }
        public static void PauseEditor()
        {
#if UNITY_EDITOR
            UnityEditor.EditorApplication.isPaused = true;
#endif
            
        }

        public static void UpdateVolumeData()
        {
            VolumeManager.instance.SetUpdateOverrideDataState(UpdateOverrideDataType.Semi_Auto);
            ((HForwardRenderer)HCameraManager.GetBaseCameraAdditionalData().scriptableRenderer).setLutbfirstTime();
        }

        public static void RelaseHangingRes()
        {
            ResidentHandler.Inst.Clear();
            JSONSerializer.FlushMem();
        }
        public static void ForceRelease()
        {
            zstring.ClearCache(); // 清空一下zstring字符串缓存

            UMTResource.Resource.ResourceManager.ForceRelease();
            UMTResource.Resource.ResourceManager.ForceRelease();
            //UMTResource.Resource.ResourceManager.ForceRelease();
            Resources.UnloadUnusedAssets();
            GC.Collect();
        }

        public static void ForceReleaseNoGC()
        {
            UMTResource.Resource.ResourceManager.ForceRelease();
            // UMTResource.Resource.ResourceManager.ForceRelease();
            // UMTResource.Resource.ResourceManager.ForceRelease();
        }

        public static void ForceReleaseNoGCStep()
        {
            Timers.inst.Add(0.02f,3, (o) =>
            {
                UMTResource.Resource.ResourceManager.ForceRelease();
            });
        }

        public static void ForceReleaseNoGCAsync(int maxPerFrame, int maxMilliseconds)
        {
            Timers.inst.StartCoroutine(UMTResource.Resource.ResourceManager.ForceReleaseAsync(maxPerFrame, maxMilliseconds));
        }

        public static void DumpLuaDelegateBridges()
        {
            LuaManager.mainState.translator.DumpAllDelegateBridges();
        }

        public static void DumpLuaHoldCsObjects()
        {
            LuaManager.mainState.translator.DumpCsObjects();
        }

        public static string IntToString(int value)
        {
            return value.ToStringNonAlloc();
        }

        private const int FileSystemMaxFileCount = 1024 * 16;
        private const int FileSystemMaxBlockCount = 1024 * 256;

        public static void RebuildFileSystem()
        {
            var resourceManager = ResourceV2Entry.Resource.ResourceManager;
            var resourceGroup = resourceManager.GetResourceGroup();
            var resourceInfos = resourceGroup.GetResourceInfos();

            var fileSystemManager = GameFrameworkEntry.GetModule<IFileSystemManager>();
            if (fileSystemManager == null)
            {
                UnityEngine.Debug.LogError($"[Resource]fileSystemManager == null");
                return;
            }

            var fileName = "data/b4/b434ad1b";

            string rawFullPath = Utility.Path.GetRegularPath(Path.Combine(resourceManager.ReadWritePath, Utility.Text.Format("{0}.dat", fileName)));
            var fileSystemIn = fileSystemManager.GetFileSystem(rawFullPath);
            if (fileSystemIn == null)
            {
                UnityEngine.Debug.LogError($"[Resource]fileSystemIn == null");
                return;
            }

            string tmpFullPath = Utility.Path.GetRegularPath(Path.Combine(resourceManager.ReadWritePath, Utility.Text.Format("{0}.tmp", fileName)));
            var fileSystemOut = fileSystemManager.CreateFileSystem(tmpFullPath, FileSystemAccess.ReadWrite, FileSystemMaxFileCount, FileSystemMaxBlockCount);
            if (fileSystemOut == null)
            {
                UnityEngine.Debug.LogError($"[Resource]fileSystemOut == null");
                return;
            }

            foreach (var pair in resourceInfos)
            {
                var resourceInfo = pair.Value;

                // 包内资源，不处理
                if (resourceInfo.StorageInReadOnly)
                    continue;

                // 非FileSystem资源，不处理
                if (!resourceInfo.UseFileSystem)
                    continue;

                // 只处理luafs
                if (resourceInfo.FileSystemName != fileName)
                    continue;

                var resourceName = pair.Key;
                //UnityEngine.Debug.Log($"[Resource]{resourceName.FullName}");
                var bytes = fileSystemIn.ReadFile(resourceName.FullName);
                fileSystemOut.WriteFile(resourceName.FullName, bytes);
            }

            fileSystemManager.DestroyFileSystem(fileSystemIn, true);
            fileSystemManager.DestroyFileSystem(fileSystemOut, false);
            File.Move(tmpFullPath, rawFullPath);
            fileSystemManager.GetFileSystem(rawFullPath);
        }

        private static IEnumerator VerifyAllResourcesAsync()
        {
            var resourceManager = ResourceV2Entry.Resource.ResourceManager;
            var resourceGroup = resourceManager.GetResourceGroup();
            var resourceInfos = resourceGroup.GetResourceInfos();
            var wrongResourceInfos = new List<ResourceManager.ResourceInfo>();
            int index = 0;
            int total = resourceInfos.Count;
            int step = 1;
            int progress = step;

            //UnityEngine.Debug.Log("[Resource]VerifyAllResourcesAsync, total = " + total);
            
            foreach (var pair in resourceInfos)
            {
                var resourceInfo = pair.Value;
                index++;
                
                if (index * 100 >= progress * total)
                {
                    ResidentHandler.Inst.GetFunction("CityLuaFunction.updateVerifyProgress").Action(progress, wrongResourceInfos.Count.ToString());
                    progress += step;
                    yield return null;
                }
                
                // 包内资源，不需要校验
                if (resourceInfo.StorageInReadOnly)
                    continue;

                // 还没下载完，不需要校验
                if (!resourceInfo.Ready)
                    continue;

                var resourceName = pair.Key;
                if (resourceInfo.UseFileSystem)
                {
                    // fileSystem

                    //UnityEngine.Debug.Log($"[Resource]开始检查: {resourceName.FullName}, fs = {resourceInfo.FileSystemName}, StorageInReadOnly = {resourceInfo.StorageInReadOnly}");
                    var assets = resourceManager.GetResourceAllAssets(resourceName.Name);
                    //UnityEngine.Debug.Log($"[Resource]GetResourceAllAssets: {resourceName.Name}, assets = {assets.Length}");


                    for (var assetIndex = 0; assetIndex < assets.Length; assetIndex++)
                    {
                        var binaryAssetName = assets[assetIndex];
                        //UnityEngine.Debug.Log($"[Resource]检查  [{assetIndex + 1}/{assets.Length}]{binaryAssetName}");
                        var bytes = resourceManager.LoadBinaryFromFileSystem(binaryAssetName);
                        // crc校验，所有对文件的操作都加try..catch
                        int crc = 0;
                        try
                        {
                            crc = Utility.Verifier.GetCrc32(bytes);
                        }
                        catch (Exception e)
                        {
                            Debug.LogException(e);
                        }

                        //UnityEngine.Debug.Log($"[Resource]检查  crc = {crc:X8}, size = {bytes.Length}, estimated crc = {resourceInfo.HashCode:X8}, size = {resourceInfo.Length}");

                        // 校验不通过，删文件
                        if (crc != resourceInfo.HashCode)
                        {
                            //UnityEngine.Debug.Log($"[Resource]校验不通过, {binaryAssetName}");
                            wrongResourceInfos.Add(resourceInfo);
                            var fileSystemManager = GameFrameworkEntry.GetModule<IFileSystemManager>();
                            if (fileSystemManager == null)
                            {
                                UnityEngine.Debug.LogError($"[Resource]fileSystemManager == null");
                                continue;
                            }
                            string fullPath = Utility.Path.GetRegularPath(Path.Combine(resourceManager.ReadWritePath, Utility.Text.Format("{0}.dat", resourceInfo.FileSystemName)));
                            var fileSystem = fileSystemManager.GetFileSystem(fullPath);
                            if (fileSystem == null)
                            {
                                UnityEngine.Debug.LogError($"[Resource]fileSystem == null, fullPath = " + fullPath);
                                continue;
                            }

                            if (!fileSystem.DeleteFile(binaryAssetName))
                            {
                                UnityEngine.Debug.LogError($"[Resource]DeleteFile failed, binaryAssetName = " + binaryAssetName);
                            }
                        }
                    }
                }
                else
                {
                    string folder = resourceManager.ReadWritePath;
                    string filePath = System.IO.Path.Combine(folder, resourceName.FullName);

                    // 文件不存在，直接GG
                    if (!File.Exists(filePath))
                    {
                        wrongResourceInfos.Add(resourceInfo);
                        continue;
                    }

                    // crc校验，所有对文件的操作都加try..catch
                    int crc = 0;
                    try
                    {
                        using (var stream = File.OpenRead(filePath))
                        {
                            crc = Utility.Verifier.GetCrc32(stream);
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);
                    }

                    // 校验不通过，删文件
                    if (crc != resourceInfo.HashCode)
                    {
                        //UnityEngine.Debug.Log($"[Resource]校验不通过, {resourceName.FullName}");
                        wrongResourceInfos.Add(resourceInfo);
                        try
                        {
                            File.Delete(filePath);
                        }
                        catch (Exception e)
                        {
                            Debug.LogException(e);
                        }
                    }
                }
            }

            resourceManager.RemoveAndDownloadWrongResources(wrongResourceInfos);
        }

        /// <summary>
        /// 校验所有资产
        /// </summary>
        public static void VerifyAllResources()
        {
            GTAGameStart.TaskScheduleCoroutineRunner.StartCoroutine(VerifyAllResourcesAsync());
        }

        /// <summary>
        /// 返回所有的资源名
        /// </summary>
        /// <returns></returns>
        public static string[] GetAllAssets()
        {
            HashSet<string> assets = new HashSet<string>();
            var resourceManager = ResourceV2Entry.Resource.ResourceManager;
            var resourceGroup = resourceManager.GetResourceGroup();
            var resourceNames = resourceGroup.GetResourceNames();
            foreach (var resourceName in resourceNames)
            {
                var assetNames = resourceManager.GetResourceAllAssets(resourceName.Replace(".dat", ""));
                foreach (var assetName in assetNames)
                {
                    if (assets.Contains(assetName))
                    {
                        UnityEngine.Debug.LogErrorFormat("重复的asset: {0} in {1}", assetName, resourceName);
                    }
                    else
                    {
                        assets.Add(assetName);
                    }
                }
            }

            var assetArray = new string[assets.Count];
            int i = 0;
            foreach (var asset in assets)
            {
                assetArray[i] = asset;
                i++;
            }

            return assetArray;
        }

        public static int GetAOTCodeVersion()
        {
            return Yoozoo.Modules.Update.GameHelper.AotCodeVersion;
        }
        public static bool IsReviewVersion()
        {
            if (Yoozoo.Modules.Update.GameHelper.AotCodeVersion > 20241021)
            {
                return _IsReviewVersion();
            }
            else
            {
                return false;
            }
             
        }

        private static bool _IsReviewVersion()
        {
            return Yoozoo.Modules.Update.GameHelper.isReviewVersion;
        }

        public static void SuperSdkSetOrientation(int orientation)
        {
            if (GetAOTCodeVersion() >= 20240910 && Gameplay.Managers.SDKManager.IsSDK())
            {
                Gameplay.Managers.SDKManager.SuperSdkSetSdkOrientation( orientation );  
            }
        }
        
        public static void TrackEvent(int eventId,int param1)
        {
            if (GetAOTCodeVersion() >= 20240910 && Gameplay.Managers.SDKManager.IsSDK())
            {
                if (eventId == (int)ETrackEvent.SuperSdkTrackFirstCreateRole)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackFirstCreateRole();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackRegister)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackRegister();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackLoadUI)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackLoadUI();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackRetention24)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackRetention24();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackRetention48)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackRetention48();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackJoinAlliance)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackJoinAlliance();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackLeaderLevel7)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackLeaderLevel7();
                }else if (eventId == (int)ETrackEvent.SuperSdkTrackMainBuildingLv)
                {
                    Gameplay.Managers.SDKManager.SuperSdkTrackMainBuildingLv(param1);
                }
            }
        }
        
        enum ETrackEvent
        {
            SuperSdkTrackFirstCreateRole = 1,
            SuperSdkTrackRegister,
            SuperSdkTrackLoadUI,
            SuperSdkTrackRetention24,
            SuperSdkTrackRetention48,
            SuperSdkTrackJoinAlliance,
            SuperSdkTrackLeaderLevel7,
            SuperSdkTrackMainBuildingLv,
        }
        
        private static readonly HashSet<string> EUCountries = new HashSet<string>
        {
            "AL", // 阿尔巴尼亚
            "AD", // 安道尔
            "AT", // 奥地利
            "BY", // 白俄罗斯
            "BE", // 比利时
            "BA", // 波斯尼亚和黑塞哥维那
            "BG", // 保加利亚
            "HR", // 克罗地亚
            "CY", // 塞浦路斯
            "CZ", // 捷克共和国
            "DK", // 丹麦
            "EE", // 爱沙尼亚
            "FO", // 法罗群岛
            "FI", // 芬兰
            "FR", // 法国
            "DE", // 德国
            "GI", // 直布罗陀
            "GR", // 希腊
            "GL", // 格陵兰
            "HU", // 匈牙利
            "IS", // 冰岛
            "IE", // 爱尔兰
            "IM", // 曼岛
            "IT", // 意大利
            "XK", // 科索沃
            "LV", // 拉脱维亚
            "LI", // 列支敦士登
            "LT", // 立陶宛
            "LU", // 卢森堡
            "MK", // 北马其顿
            "MT", // 马耳他
            "MD", // 摩尔多瓦
            "MC", // 摩纳哥
            "ME", // 黑山
            "NL", // 荷兰
            "NO", // 挪威
            "PL", // 波兰
            "PT", // 葡萄牙
            "RO", // 罗马尼亚
            "RU", // 俄罗斯
            "SM", // 圣马力诺
            "RS", // 塞尔维亚
            "SK", // 斯洛伐克
            "SI", // 斯洛文尼亚
            "ES", // 西班牙
            "SE", // 瑞典
            "CH", // 瑞士
            "UA", // 乌克兰
            "GB", // 英国
            "JE", // 泽西岛
            "GG", // 根西岛
            "VA", // 梵蒂冈城
            "AD", // 安道尔
            "MT", // 马耳他
            "PT", // 葡萄牙
            "RO", // 罗马尼亚
            "RU", // 俄罗斯
            "SM", // 圣马力诺
            "RS", // 塞尔维亚
            "SK", // 斯洛伐克
            "SI", // 斯洛文尼亚
            "ES", // 西班牙
            "SE", // 瑞典
            "CH", // 瑞士
            "UA", // 乌克兰
            "GB", // 英国
            "JE", // 泽西岛
            "GG", // 根西岛
            "VA"  // 梵蒂冈城
        };
        
        public static bool IsEURegion(string countryCode = null)
        {
            if (Yoozoo.Modules.Update.GameHelper.AotCodeVersion >= 20241014)
            {
                return IsEURegionInternal(countryCode);
            }

            return true;
        }
        /// <summary>
        /// </summary>
        /// <param name="countryCode"></param>
        /// <returns></returns>
        private static bool IsEURegionInternal(string countryCode)
        {
            if (string.IsNullOrEmpty(countryCode))
            {
                if (SDKManager.IsSDK() && SDKManager.SuperSdkInitSuccess())
                {
                    countryCode = SDKManager.GetCountry();
                }
                else
                {
                    countryCode =RegionInfo.CurrentRegion.TwoLetterISORegionName;  //IOS 有问题
                }
            }
            return EUCountries.Contains(countryCode.ToUpper());
        }
    }
}
